Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

修复initrd在新linux内核中无法加载的问题 #3082

Merged
merged 1 commit into from
Jan 22, 2025

Conversation

jjm2473
Copy link
Contributor

@jjm2473 jjm2473 commented Jan 14, 2025

这个补丁应该可以修复initrd在新linux内核中无法加载的问题 ventoy/OpenWrtPlugin#8

受影响linux版本(根据 https://www.cve.org/CVERecord/?id=CVE-2024-53142 ):

from 0 before 2.6.12
from 4.19.325 through 4.19.*
from 5.4.287 through 5.4.*
from 5.10.231 through 5.10.*
from 5.15.174 through 5.15.*
from 6.1.120 through 6.1.*
from 6.6.64 through 6.6.*
from 6.11.11 through 6.11.*
from 6.12.2 through 6.12.*
from 6.13-rc1

补丁来自 rhboot/grub2@544fd63

以下是原始补丁的提交信息:

loader/linux: Ensure the newc pathname is NULL-terminated

Per "man 5 cpio", the namesize in the cpio header includes the trailing NUL byte of the pathname and the pathname is followed by NUL bytes, but the current implementation ignores the trailing NUL byte when making the newc header. Although make_header() tries to pad the pathname string, the padding won't happen when strlen(name) + sizeof(struct newc_head) is a multiple of 4, and the non-NULL-terminated pathname may lead to unexpected results.

Assume that a file is created with 'echo -n aaaa > /boot/test12' and loaded by grub2:

    linux /boot/vmlinuz
    initrd newc:test12:/boot/test12 /boot/initrd

The initrd command eventually invoked grub_initrd_load() and sent 't''e''s''t''1''2' to make_header() to generate the header:

00000070  30 37 30 37 30 31 33 30  31 43 41 30 44 45 30 30  |070701301CA0DE00| 00000080  30 30 38 31 41 34 30 30  30 30 30 33 45 38 30 30  |0081A4000003E800| 00000090  30 30 30 30 36 34 30 30  30 30 30 30 30 31 36 33  |0000640000000163| 000000a0  37 36 45 34 35 32 30 30  30 30 30 30 30 34 30 30  |76E4520000000400| 000000b0  30 30 30 30 30 38 30 30  30 30 30 30 31 33 30 30  |0000080000001300| 000000c0  30 30 30 30 30 30 30 30  30 30 30 30 30 30 30 30  |0000000000000000| 000000d0  30 30 30 30 30 36 30 30  30 30 30 30 30 30 74 65  |00000600000000te|
                                                                  ^namesize
000000e0  73 74 31 32 61 61 61 61  30 37 30 37 30 31 30 30  |st12aaaa07070100|
                   ^^ end of the pathname

Since strlen("test12") + sizeof(struct newc_head) is 116 = 29 * 4, make_header() didn't pad the pathname, and the file content followed "test12" immediately. This violates the cpio format and may trigger such error during linux boot:

    Initramfs unpacking failed: ZSTD-compressed data is trunc

To avoid the potential problems, this commit counts the trailing NUL byte in when calling make_header() and adjusts the initrd size accordingly.

Now the header becomes

00000070  30 37 30 37 30 31 33 30  31 43 41 30 44 45 30 30  |070701301CA0DE00| 00000080  30 30 38 31 41 34 30 30  30 30 30 33 45 38 30 30  |0081A4000003E800| 00000090  30 30 30 30 36 34 30 30  30 30 30 30 30 31 36 33  |0000640000000163| 000000a0  37 36 45 34 35 32 30 30  30 30 30 30 30 34 30 30  |76E4520000000400| 000000b0  30 30 30 30 30 38 30 30  30 30 30 30 31 33 30 30  |0000080000001300| 000000c0  30 30 30 30 30 30 30 30  30 30 30 30 30 30 30 30  |0000000000000000| 000000d0  30 30 30 30 30 37 30 30  30 30 30 30 30 30 74 65  |00000700000000te|
                                                                  ^namesize
000000e0  73 74 31 32 00 00 00 00  61 61 61 61 30 37 30 37  |st12....aaaa0707|
                      ^^ end of the pathname

Besides the trailing NUL byte, make_header() pads 3 more NUL bytes, and the user can safely read the pathname without a further check.

To conform to the cpio format, the headers for "TRAILER!!!" are also adjusted to include the trailing NUL byte, not ignore it.


Reviewed-by: Daniel Kiper <[email protected]>

Per "man 5 cpio", the namesize in the cpio header includes the trailing
NUL byte of the pathname and the pathname is followed by NUL bytes, but
the current implementation ignores the trailing NUL byte when making
the newc header. Although make_header() tries to pad the pathname string,
the padding won't happen when strlen(name) + sizeof(struct newc_head)
is a multiple of 4, and the non-NULL-terminated pathname may lead to
unexpected results.

Assume that a file is created with 'echo -n aaaa > /boot/test12' and
loaded by grub2:

    linux /boot/vmlinuz
    initrd newc:test12:/boot/test12 /boot/initrd

The initrd command eventually invoked grub_initrd_load() and sent
't''e''s''t''1''2' to make_header() to generate the header:

00000070  30 37 30 37 30 31 33 30  31 43 41 30 44 45 30 30  |070701301CA0DE00|
00000080  30 30 38 31 41 34 30 30  30 30 30 33 45 38 30 30  |0081A4000003E800|
00000090  30 30 30 30 36 34 30 30  30 30 30 30 30 31 36 33  |0000640000000163|
000000a0  37 36 45 34 35 32 30 30  30 30 30 30 30 34 30 30  |76E4520000000400|
000000b0  30 30 30 30 30 38 30 30  30 30 30 30 31 33 30 30  |0000080000001300|
000000c0  30 30 30 30 30 30 30 30  30 30 30 30 30 30 30 30  |0000000000000000|
000000d0  30 30 30 30 30 36 30 30  30 30 30 30 30 30 74 65  |00000600000000te|
                                                                  ^namesize
000000e0  73 74 31 32 61 61 61 61  30 37 30 37 30 31 30 30  |st12aaaa07070100|
                   ^^ end of the pathname

Since strlen("test12") + sizeof(struct newc_head) is 116 = 29 * 4,
make_header() didn't pad the pathname, and the file content followed
"test12" immediately. This violates the cpio format and may trigger such
error during linux boot:

    Initramfs unpacking failed: ZSTD-compressed data is trunc

To avoid the potential problems, this commit counts the trailing NUL byte
in when calling make_header() and adjusts the initrd size accordingly.

Now the header becomes

00000070  30 37 30 37 30 31 33 30  31 43 41 30 44 45 30 30  |070701301CA0DE00|
00000080  30 30 38 31 41 34 30 30  30 30 30 33 45 38 30 30  |0081A4000003E800|
00000090  30 30 30 30 36 34 30 30  30 30 30 30 30 31 36 33  |0000640000000163|
000000a0  37 36 45 34 35 32 30 30  30 30 30 30 30 34 30 30  |76E4520000000400|
000000b0  30 30 30 30 30 38 30 30  30 30 30 30 31 33 30 30  |0000080000001300|
000000c0  30 30 30 30 30 30 30 30  30 30 30 30 30 30 30 30  |0000000000000000|
000000d0  30 30 30 30 30 37 30 30  30 30 30 30 30 30 74 65  |00000700000000te|
                                                                  ^namesize
000000e0  73 74 31 32 00 00 00 00  61 61 61 61 30 37 30 37  |st12....aaaa0707|
                      ^^ end of the pathname

Besides the trailing NUL byte, make_header() pads 3 more NUL bytes, and
the user can safely read the pathname without a further check.

To conform to the cpio format, the headers for "TRAILER!!!" are also
adjusted to include the trailing NUL byte, not ignore it.

Signed-off-by: Gary Lin <[email protected]>
Reviewed-by: Daniel Kiper <[email protected]>
@ventoy ventoy merged commit f43461a into ventoy:master Jan 22, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants